


public class streamer {
	private int moviesAmountInStreamer 	= 4; 	// N
	private int moviesAmountInPC 		= 500; 	// M
	private int[] loadedMovies;
	private node[] moviesInStreamer;
	private linkedList listByPlayCount;
	private int indexOfMoviesInStreamer;
	private int insertionIndex;
	private int lastPlayedMovie;
	private int maxNumberOfSuccesivePlays;
	private int mostPlayedMovieInSequence;
	private int numberOfReplacments;
	private String outputFileName;
	
	public streamer(int n,int m , String outputFileName){
		this.moviesAmountInStreamer = n;
		this.moviesAmountInPC = m;
		this.outputFileName = outputFileName;
	}
	
	
	public static void main(String[] args) {
//		if ((args.length != 2) || 
//			(args.length != 3)){
//			System.out.println("Expecting 2 arguments:");
//			System.out.println("    1. Configurations input file.");
//			System.out.println("    2. Output file.");
//			System.exit(1);
//		}
			
		fileHandler fh = new fileHandler(args[0], args[1]);
		
		System.out.println(fh.toString());
		
		System.out.println("Streamer started");
		streamer stream = new streamer(4,500,"output.txt");
		stream.Int();
	
		stream.Play(1);
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
  		stream.Play(1);   
  		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
  		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
  		stream.Play(1);   
  		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
  		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		stream.Play(2);   
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
  		stream.Play(2);  
  		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
  		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		stream.Play(2);    
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		stream.Play(3);   
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		stream.Play(3);  
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		stream.Play(4);   
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		stream.Play(4);   
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		stream.Play(5);   
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		stream.Play(6);    
		System.out.println("most played movie in sequance is " + stream.MostSequentiallyPlayedMovie());
		System.out.println("the number of replacements is : " + stream.ReplacementsNumber());
		System.out.println(stream.toString());
		
//		stream.Play(1);
//		stream.Play(2);
//		stream.Play(3);
//		stream.Play(1);
//		stream.Play(2);
//		stream.Play(3);
//		stream.Play(1);
//		stream.Play(2);
//		stream.Play(3);
		
	
	}
	
	public  void Int(){
		this.loadedMovies 			                     = new int[moviesAmountInPC + 1]; 
		this.moviesInStreamer 		                     = new node [moviesAmountInStreamer + 1];
		this.listByPlayCount 		                     = new linkedList();
		this.indexOfMoviesInStreamer                     = 1;
		this.lastPlayedMovie 		                     = -1;
		this.maxNumberOfSuccesivePlays                   = 1;
		this.mostPlayedMovieInSequence	                 = -1;
		this.numberOfReplacments						 = 0;
		
			
		
	}
	
	public void Play(int movie){

		//		if (this.lastPlayedMovie == movie){									//if the last movie that was played and the new movie are the same , we update the currentNumberOfSuccesivePlays field.
//			this.currentNumberOfSuccesivePlays++;							//if not , we bring in back to zero
//		}else{
//			this.currentNumberOfSuccesivePlays = 0;
//		}
		int isInStreamer = isInStreamer(movie);
		
		if (isInStreamer != 0){
			System.out.println("in the if of play ! the movie number is : "+movie);
			node nodeOfMovieToPlay = this.moviesInStreamer[isInStreamer];
			nodeDataByTime nodeDataOfMovieToPlay = (nodeDataByTime)nodeOfMovieToPlay.data;
			node fatherOfNodeOfMovieToPlay = nodeDataOfMovieToPlay.playCountNode;
			((nodeDataByPlayCount)fatherOfNodeOfMovieToPlay.data).listByTime.removeNode(nodeOfMovieToPlay);
			node possibleFatherOfMovie = fatherOfNodeOfMovieToPlay.next; 
			deleteEmptyBranch(nodeDataOfMovieToPlay);
			
			nodeDataOfMovieToPlay.playCount++;
			
			if(nodeDataOfMovieToPlay.movieInPc == this.lastPlayedMovie){			// we update the number of rapid plays in the movie node. (we don't need to do this in 'insert' function because only movies in the streamer can be played in rapid succesion.)
				nodeDataOfMovieToPlay.playedInRapidSuccession++;
			}
			if (this.maxNumberOfSuccesivePlays <= nodeDataOfMovieToPlay.playedInRapidSuccession){	// update the streamer's most played movie in succession field.
				this.mostPlayedMovieInSequence = nodeDataOfMovieToPlay.movieInPc;
				this.maxNumberOfSuccesivePlays = nodeDataOfMovieToPlay.playedInRapidSuccession;
			}
			
			insertionIndex = isInStreamer;
			rearrenge(possibleFatherOfMovie, nodeDataOfMovieToPlay.playCount, nodeDataOfMovieToPlay);
			
			
			
			
//			(((nodeDataByPlayCount).playCountNode.data).listByTime
			
		}else{
			insert(movie);
		}
		this.lastPlayedMovie = movie;
		
	}
	
	private int isInStreamer (int m){			//if movie is in streamer return it's index in the streamer , else returns zero
		return this.loadedMovies[m];		 
	}
	
	private boolean isFreeSpaceAvailableForMovie(){						// if it's possible to insert a movie without removing it from the streamer returns 'true' else returns 'false'
		return this.indexOfMoviesInStreamer <= moviesAmountInStreamer;
	}
	
	public int ReplacementsNumber(){
		return this.numberOfReplacments;
	}
	
	private void insert(int m){
		
		if (isFreeSpaceAvailableForMovie()){
			insertionIndex = indexOfMoviesInStreamer;
			indexOfMoviesInStreamer++;
		}else{
			delete();
			// TODO: count here for ReplacementsNumber()
			this.numberOfReplacments++;
			
		}
		System.out.println("There is still space , one movie " + m + " will be inserted.");
		
		loadedMovies[m]=insertionIndex;								// places the index of the movie's destination in the movie's on pc array.
		node tailNode = listByPlayCount.peekTail();
		
		nodeDataByTime newMovieData = new nodeDataByTime();					//we create date for the TimeStamp list.
		newMovieData.movieInPc = m;                  
		newMovieData.movieInStreamer = this.insertionIndex;            
		       
		newMovieData.playCount = 1;                  
		newMovieData.playedInRapidSuccession = 0;
		
		rearrenge (tailNode , 1 , newMovieData);
		
//		if ((tailNode == null) || (((nodeDataByPlayCount)tailNode.data).playCount != 1)){													//if the play by count list is empty , we create a new list and put the movie in it's right place.
//			nodeDataByPlayCount newMovie = new nodeDataByPlayCount();			//we make a data for the Playcount list  
//			newMovie.playCount = 1;												//the number of playes for this movie is 1 because its new.
//			newMovie.listByTime = new linkedList();								 
//							
//											
//			newMovieData.playCountNode = listByPlayCount.addToTail(newMovie);	//we push the new link to the end of the list
//			
//			this.moviesInStreamer[insertionIndex] = newMovie.listByTime.addToHead(newMovieData); //
//			
//		}else{
//			
//			this.moviesInStreamer[insertionIndex] = ((nodeDataByPlayCount)tailNode.data).listByTime.addToHead(newMovieData);		
//			newMovieData.playCountNode = tailNode;
//			
//		}
		
	}
	
	private void delete(){
		node temp = (node)this.listByPlayCount.peekTail();										//we peek inside the the list with the least plays
		nodeDataByPlayCount dataByPlayCount = ((nodeDataByPlayCount)temp.data);
		nodeDataByTime removedMovie = (nodeDataByTime)dataByPlayCount.listByTime.removeTail();	//from the list with the least play counts we remove the oldest movie  
		this.insertionIndex = removedMovie.movieInStreamer;										//We update the index of the space in the streamer that now can host another movie.
		
		deleteEmptyBranch ( removedMovie );
		
		System.out.println("movie "+removedMovie.movieInPc+" was deleted");
		
	}
	
	private void deleteEmptyBranch (nodeDataByTime dataOfSonOfDeleteCandedate){										//deletes the branch if it has no sons.
		if (((nodeDataByPlayCount)dataOfSonOfDeleteCandedate.playCountNode.data).listByTime.size() == 0){		
			this.listByPlayCount.removeNode(dataOfSonOfDeleteCandedate.playCountNode);
			
		}
	}
	
	
	private void rearrenge (node possibleFatherOfMovie , int playCount , nodeDataByTime movieData){
		
			
	
			
			if ((possibleFatherOfMovie == null) || (((nodeDataByPlayCount)possibleFatherOfMovie.data).playCount != playCount)){													//if the play by count list is empty , we create a new list and put the movie in it's right place.
				nodeDataByPlayCount dataOfFatherOfMovie = new nodeDataByPlayCount();			//we make a data for the Playcount list  
				dataOfFatherOfMovie.playCount = playCount;												//the number of playes for this movie is 1 because its new.
				dataOfFatherOfMovie.listByTime = new linkedList();								 
								
												
				movieData.playCountNode = listByPlayCount.AddToListBeforeNode(possibleFatherOfMovie, dataOfFatherOfMovie);	//we push the new link to the end of the list
				
				this.moviesInStreamer[insertionIndex] = dataOfFatherOfMovie.listByTime.addToHead(movieData); //
				
			}else{
				
				this.moviesInStreamer[insertionIndex] = ((nodeDataByPlayCount)possibleFatherOfMovie.data).listByTime.addToHead(movieData);		
				movieData.playCountNode = possibleFatherOfMovie;
				
			}
	}
	
	public int MostSequentiallyPlayedMovie (){
		return this.mostPlayedMovieInSequence;
	}
	
	public String toString(){
		String ans = "";
		int playCount = 0 ;
		int movieName = -1;
		node temp = this.listByPlayCount.peekTail();
		
		while (temp != null){
			linkedList templist = ((nodeDataByPlayCount)temp.data).listByTime;
			
			playCount = ((nodeDataByPlayCount)temp.data).playCount ;
			ans =ans + playCount+":";
			node tempNodeByTime = templist.peekTail();
			
			while (tempNodeByTime != null){
				
				movieName = ((nodeDataByTime)tempNodeByTime.data).movieInPc;
				ans = ans+"m"+movieName+',';
				
				tempNodeByTime = tempNodeByTime.next;
			}
			ans = ans+"\n"; 
			temp = temp.next;
		}
		return ans;
		
	}
	
	
	


	
}


